#include "iocpsocketmgr.h"
#include "iocpnetmgr.h"

CIocpSocketMgr::CIocpSocketMgr( CIocpNetMgr* iocp_net_mgr )
{
    m_iocp_net_mgr = iocp_net_mgr;
}

CIocpSocketMgr::~CIocpSocketMgr(void)
{
}

bool CIocpSocketMgr::Init( void )
{
    if (!m_pool_iocp_socket.Init(m_iocp_net_mgr->GetIocpSetting(IOCP_SETTING_MAX_SOCKET)))
        return false;

    if (!m_pool_listener.Init(64))
        return false;

    m_timer_mgr = CreateTimerManager(this);
    if (!m_timer_mgr)
        return false;

    return true;
}

void CIocpSocketMgr::UnInit( void )
{

}

CIocpSocket* CIocpSocketMgr::AllocSocket( void )
{
    m_alloc_socket_lock.Lock();
    CIocpSocket* iocp_socket = m_pool_iocp_socket.AllocObj();
    m_alloc_socket_lock.UnLock();
    if (iocp_socket)
    {
        iocp_socket->Reset();
        iocp_socket->m_iocp_net_mgr = m_iocp_net_mgr;
        return iocp_socket;
    }

    return NULL;
}

void CIocpSocketMgr::FreeSocket( CIocpSocket* iocp_socket )
{
    if (iocp_socket)
    {
        iocp_socket->FreeDataBuf();
        m_alloc_socket_lock.Lock();
        m_pool_iocp_socket.FreeObj(iocp_socket);
        m_alloc_socket_lock.UnLock();
    }
}

CIocpListener* CIocpSocketMgr::AllocListener( void )
{
    CIocpListener* iocp_listener = m_pool_listener.AllocObj();
    if (iocp_listener)
    {
        return iocp_listener;
    }

    return NULL;
}

void CIocpSocketMgr::FreeListener( CIocpListener* listener )
{
    if (listener)
    {
        m_pool_listener.FreeObj(listener);
    }
}

CIocpSocket* CIocpSocketMgr::Session2Socket( HSESSION session )
{
    if (m_pool_iocp_socket.IsAllocByPool((CIocpSocket*)session))
    {
        return (CIocpSocket*)session;
    }

    return NULL;
}

CIocpListener* CIocpSocketMgr::NetHandle2Listener( HNETHANDLE net_handle )
{
    if (m_pool_listener.IsAllocByPool((CIocpListener*)net_handle))
    {
        return (CIocpListener*)net_handle;
    }

    return NULL;
}

bool CIocpSocketMgr::Update( void )
{
    return m_timer_mgr->Update();
}

bool CIocpSocketMgr::ModTimer( CIocpSocket& iocp_socket, INT32 elapse, INT32 count )
{
    if (elapse <= 0)
    {
        if (iocp_socket.GetTimer())
        {
            m_timer_mgr->DelTimer(iocp_socket.GetTimer());
            iocp_socket.SetTimer(NULL);
        }

        if (iocp_socket.m_data_delay_send > 0)
        {
            if (0 == ::InterlockedExchangeAdd(&iocp_socket.m_data_to_send, iocp_socket.m_data_delay_send))
            {
                if (!iocp_socket.PostSendReq())
                {
                    iocp_socket.Close(NET_SYSTEM_ERROR);
                }
            }
        }

        iocp_socket.m_data_delay_send = 0;

        return true;
    }

    if (iocp_socket.GetTimer())
    {
        return m_timer_mgr->ModTimer(iocp_socket.GetTimer(), elapse, count, &iocp_socket);
    }

    HTIMER timer = m_timer_mgr->AddTimer(elapse, count, &iocp_socket);
    if (!timer)
    {
        return false;
    }

    iocp_socket.SetTimer(timer);
    iocp_socket.m_data_delay_send = 0;

    return true;
}

void CIocpSocketMgr::OnTimer( HTIMER hTimer, void* pData )
{
    CIocpSocket* iocp_socket = (CIocpSocket*)pData;

    if (iocp_socket->GetTimer() == hTimer)
    {
        iocp_socket->OnTimer();
    }
}

char* CIocpSocketMgr::AllocBuf( UINT32 dwSize )
{
    char* pBuf = NULL;
    m_alloc_buf_lock.Lock();
    CBufferPool::iterator itBufList = m_oBufPool.find(dwSize);
    if (itBufList == m_oBufPool.end())
    {
        CBufferDeque oBufferList;
        m_oBufPool[dwSize] = oBufferList;

        pBuf = new char[dwSize];
        if (NULL == pBuf)
        {
            m_alloc_buf_lock.UnLock();
            return NULL;
        }
        m_alloc_buf_lock.UnLock();
        return pBuf;
    }

    if (itBufList->second.empty())
    {
        pBuf = new char[dwSize];
        if (NULL == pBuf)
        {
            m_alloc_buf_lock.UnLock();
            return NULL;
        }
        m_alloc_buf_lock.UnLock();
        return pBuf;
    }

    pBuf = itBufList->second.front();
    itBufList->second.pop_front();
    m_alloc_buf_lock.UnLock();

    return pBuf;
}

void CIocpSocketMgr::FreeBuf( char* pBuf, UINT32 dwSize )
{
    if (NULL == pBuf || 0 == dwSize)
    {
        return;
    }

    m_alloc_buf_lock.Lock();
    CBufferPool::iterator itBufList = m_oBufPool.find(dwSize);

    if (itBufList == m_oBufPool.end())
    {
        delete[] pBuf;
        m_alloc_buf_lock.UnLock();
        return;
    }

    itBufList->second.push_back(pBuf);
    m_alloc_buf_lock.UnLock();
}

void CIocpSocketMgr::DelTimer( CIocpSocket& iocp_socket )
{
    if (iocp_socket.GetTimer())
    {
        m_timer_mgr->DelTimer(iocp_socket.GetTimer());
        iocp_socket.SetTimer(NULL);
    }
}


